using System;
using System.Windows;
using System.Windows.Controls;

namespace Columbus.Controls
{
    /// <summary>
    /// Navigation frame is used to display content (action results)
    /// </summary>
    public class Frame : ContentControl
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Frame"/> class.
        /// </summary>
        public Frame()
        {
            DefaultStyleKey = typeof(Frame);
        }

        public static readonly DependencyProperty IsNavigationInProgressProperty = DependencyProperty.Register("IsNavigationInProgress", typeof(bool), typeof(Frame), new PropertyMetadata(false));
        public static readonly DependencyProperty IsAllowedToCancelProperty = DependencyProperty.Register("IsAllowedToCancel", typeof(bool), typeof(Frame), new PropertyMetadata(false));
        public static readonly DependencyProperty IsContentEnabledProperty = DependencyProperty.Register("IsContentEnabled", typeof(bool), typeof(Frame), new PropertyMetadata(true));
        public static readonly DependencyProperty IsGoBackButtonIntegratedProperty = DependencyProperty.Register("IsGoBackButtonIntegrated", typeof(bool), typeof(Frame), new PropertyMetadata(false));
        public static readonly DependencyProperty ProgressIndicatorProperty = DependencyProperty.Register("ProgressIndicator", typeof(object), typeof(Frame), new PropertyMetadata("Loading..."));
        public static readonly DependencyProperty DialogProperty = DependencyProperty.Register("Dialog", typeof(object), typeof(Frame), new PropertyMetadata(null));
        public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register("Progress", typeof(object), typeof(Frame), new PropertyMetadata(0));
        public static readonly DependencyProperty CancelButtonContentProperty = DependencyProperty.Register("CancelButtonContent", typeof(object), typeof(Frame), new PropertyMetadata("Cancel navigation"));

        public static readonly DependencyProperty IsContentDisplayedProperty = DependencyProperty.Register("IsContentDisplayed", typeof(bool), typeof(Frame), new PropertyMetadata(false));
        public static readonly DependencyProperty IsDialogDisplayedProperty = DependencyProperty.Register("IsDialogDisplayed", typeof(bool), typeof(Frame), new PropertyMetadata(false));

        /// <summary>
        /// Gets or sets action execution progress.
        /// </summary>
        /// <value>Execution progress.</value>
        public object Progress
        {
            get { return GetValue(ProgressProperty); }
            set { SetValue(ProgressProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether navigation is in progress.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if navigation is in progress; otherwise, <c>false</c>.
        /// </value>
        public bool IsNavigationInProgress
        {
            get { return (bool)GetValue(IsNavigationInProgressProperty); }
            set { SetValue(IsNavigationInProgressProperty, value); }
        }

        /// <summary>
        /// Gets or sets progress indicator content.
        /// </summary>
        /// <value>Progress indicator.</value>
        public object ProgressIndicator
        {
            get { return GetValue(ProgressIndicatorProperty); }
            set { SetValue(ProgressIndicatorProperty, value); }
        }

        /// <summary>
        /// Gets or sets dialog view.
        /// </summary>
        /// <value>Dialog.</value>
        public object Dialog
        {
            get { return GetValue(DialogProperty); }
            set { SetValue(DialogProperty, value); }
        }

        /// <summary>
        /// Gets or sets content of 'Cancel' button (button for cancelling execution progress).
        /// </summary>
        /// <value>Content of 'Cancel' button.</value>
        public object CancelButtonContent
        {
            get { return GetValue(CancelButtonContentProperty); }
            set { SetValue(CancelButtonContentProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether action is allowed to be cancelled.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if action is allowed to be cancelled; otherwise, <c>false</c>.
        /// </value>
        public bool IsAllowedToCancel
        {
            get { return (bool)GetValue(IsAllowedToCancelProperty); }
            set { SetValue(IsAllowedToCancelProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this navigation framne content is enabled.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if navigation frame content is enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsContentEnabled
        {
            get { return (bool)GetValue(IsContentEnabledProperty); }
            set { SetValue(IsContentEnabledProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this navigation frame is integrated with phone 'Back' button.
        /// When frame is integrated with phone 'Back' button, it navigates back when phone 'Back' button is pressed.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this frame is integrated with phone 'Back' button; otherwise, <c>false</c>.
        /// </value>
        public bool IsGoBackButtonIntegrated
        {
            get { return (bool)GetValue(IsGoBackButtonIntegratedProperty); }
            set { SetValue(IsGoBackButtonIntegratedProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether navigation frame content is displayed.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if navigation frame content is displayed; otherwise, <c>false</c>.
        /// </value>
        public bool IsContentDisplayed
        {
            get { return (bool)GetValue(IsContentDisplayedProperty); }
            set { SetValue(IsContentDisplayedProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether dialog is displayed.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if dialog is displayed; otherwise, <c>false</c>.
        /// </value>
        public bool IsDialogDisplayed
        {
            get { return (bool)GetValue(IsDialogDisplayedProperty); }
            set { SetValue(IsDialogDisplayedProperty, value); }
        }

        /// <summary>
        /// Called when navigation is started.
        /// </summary>
        /// <param name="direction"></param>
        public void OnNavigationStarted(NavigationDirection direction)
        {
            NavigationDirection = direction;
            IsContentEnabled = false;
            Dialog = null;
            IsDialogDisplayed = false;
            IsNavigationInProgress = true;
            Progress = null;
        }

        protected NavigationDirection NavigationDirection { get; private set; }

        /// <summary>
        /// Called when navigation is completed.
        /// </summary>
        public void OnNavigationCompleted()
        {
            IsAllowedToCancel = false;
            IsNavigationInProgress = false;
        }

        /// <summary>
        /// Shows specified view in this navigation frame.
        /// </summary>
        /// <param name="view">View.</param>
        public void Show(FrameworkElement view)
        {
            IsContentEnabled = true;
            IsContentDisplayed = true;
            Content = view;
        }

        /// <summary>
        /// Shows specified dialog in this navigation frame.
        /// </summary>
        /// <param name="view">View.</param>
        public void ShowDialog(FrameworkElement view)
        {
            IsContentEnabled = false;
            IsDialogDisplayed = true;
            Dialog = view;
        }

        /// <summary>
        /// Closes the dialog that is currently active in the navigation frame.
        /// </summary>
        public void CloseDialog()
        {
            IsDialogDisplayed = false;

            Show(Content as FrameworkElement);
        }

        /// <summary>
        /// Occurs when navigation is canceled.
        /// </summary>
        public event Action NavigationCanceled = () => { };

        /// <summary>
        /// When overridden in a derived class, is invoked whenever application code or internal processes (such as a rebuilding layout pass) call <see cref="M:System.Windows.Controls.Control.ApplyTemplate"/>. In simplest terms, this means the method is called just before a UI element displays in an application. For more information, see Remarks.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var cancelButton = GetTemplateChild("PART_CancelButton") as Button;
            if (cancelButton != null)
                cancelButton.Click += (x, y) => NavigationCanceled();
        }
    }
}